package com.wu.family.publish.photo;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;


import com.idle.view.TouchFocusView;
import com.idle.view.TouchFocusView.OnTouchInterface;
import com.wu.family.BaseActivity;
import com.wu.family.MainGroupActivity;
import com.wu.family.R;
import com.wu.family.config.Constant;
import com.wu.family.publish.photo.utils.CameraHelper;
import com.wu.family.publish.photo.utils.CameraHelper.CameraInfo2;
import com.wu.family.utils.BitmapTools;
import com.wu.family.views.GridLineView;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class CustomCameraNewActivity extends BaseActivity implements OnClickListener, SensorEventListener{
	private LinearLayout llLlTitle;
	private RelativeLayout rlPreview;
	private FrameLayout flFlPreview;
	private GridLineView glView;
	private TouchFocusView touchFocusView;
	private LinearLayout llLlBottom2;
	private ImageButton ibBtnCamera;
	
	private LinearLayout llLlBottom;
	private ImageButton ibBtnClose;
	private ImageButton ibBtnGridline;
	private ImageButton ibBtnSwitch;
	private ImageButton ibBtnFlashing;
	
	private CameraPreview mPreview;
	private SensorManager sensorManager = null;
	private CameraHelper mCameraHelper;
    private CameraLoader mCamera;
    
    private Context context;
    private int degrees = -1;
    private int orientation;
    
	private String topicid;
	private boolean fromTopic = false;
	private String tagname;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.custom_camera_new);
		context = this;
		
		fromTopic = getIntent().getBooleanExtra("fromTopic", false);
		topicid = getIntent().getStringExtra("topicid");
		tagname = getIntent().getStringExtra("tagname");
		tagname = (tagname!=null)?tagname:"";
		
		sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); 
		mCameraHelper = new CameraHelper(this);
        mCamera = new CameraLoader();
        
		initView();
        initEvent();
        BitmapTools.recycleFeedOfBm(this);
        
	}
	
    private void initView() {
    	llLlTitle = (LinearLayout) findViewById( R.id.llTitle );
    	rlPreview = (RelativeLayout) findViewById( R.id.rlPreview );
    	
    	flFlPreview = (FrameLayout) findViewById( R.id.flPreview );
    	glView = (GridLineView) findViewById( R.id.glView );
    	touchFocusView = (TouchFocusView) findViewById( R.id.tfView );
    	llLlBottom2 = (LinearLayout) findViewById( R.id.llBottom2 );
    	ibBtnCamera = (ImageButton) findViewById( R.id.btnCamera );
    	llLlBottom = (LinearLayout) findViewById( R.id.llBottom );
    	ibBtnClose = (ImageButton) findViewById( R.id.btnClose );
    	ibBtnGridline = (ImageButton) findViewById( R.id.btnGridline );
    	ibBtnSwitch = (ImageButton) findViewById( R.id.btnSwitch );
    	ibBtnFlashing = (ImageButton) findViewById( R.id.btnFlashing );
    	
    	ViewGroup.LayoutParams lp = rlPreview.getLayoutParams();
  		lp.height = screenWidth;
  		rlPreview.setLayoutParams(lp);
  		
    	if (!mCameraHelper.hasFrontCamera() || !mCameraHelper.hasBackCamera()) {
    		ibBtnSwitch.setVisibility(View.GONE);
        }
	}


	private void initEvent() {
		llLlTitle.setOnClickListener( this );
		flFlPreview.setOnClickListener( this );
		llLlBottom2.setOnClickListener( this );
		ibBtnCamera.setOnClickListener( this );
		llLlBottom.setOnClickListener( this );
		ibBtnClose.setOnClickListener( this );
		ibBtnGridline.setOnClickListener( this );
		ibBtnSwitch.setOnClickListener( this );
		ibBtnFlashing.setOnClickListener( this );
		
		touchFocusView.setAutoDismiss(false);
		touchFocusView.setOnTouchInterface(new OnTouchInterface() {
			@Override
			public void OnTouch(float fx, float fy) {
				mCamera.mCameraInstance.autoFocus(new AutoFocusCallback() {
					@Override
					public void onAutoFocus(boolean success, Camera camera) {
						touchFocusView.setIconVisible(false);
					}
				});
			}
		}); 
	}
	
	@Override
	public void onClick(View v) {
		if(v == ibBtnClose){
			finish();
		}else if (v == ibBtnCamera) {
			if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
				/*if (mCamera.mCameraInstance.getParameters().getFocusMode().equals(
                        Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {//PICTURE
                    takePicture();
                } else */{
                	setViewEnable(false);
                    mCamera.mCameraInstance.autoFocus(new Camera.AutoFocusCallback() {

                        @Override
                        public void onAutoFocus(final boolean success, final Camera camera) {
                            takePicture();
                        }
                    });
                }
			}else{
				Toast.makeText(context, "please insert SD card.", Toast.LENGTH_SHORT).show();
			}
		}else if (v == ibBtnGridline) {
			glView.setVisibility(glView.isShown()?View.GONE:View.VISIBLE);
		}else if (v == ibBtnSwitch) {
			mCamera.switchCamera();
		}else if (v == ibBtnFlashing) {
			Integer tag = (Integer)ibBtnFlashing.getTag();
			tag = (tag == null)?0:tag;
			tag = tag%3;
			if (tag == 0) {
				mCamera.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
				ibBtnFlashing.setImageResource(R.drawable.flashing_on);
			}else if (tag == 1) {
				mCamera.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
				ibBtnFlashing.setImageResource(R.drawable.flashing_auto);
			}else {
				mCamera.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
				ibBtnFlashing.setImageResource(R.drawable.flashing_off);
			}
			ibBtnFlashing.setTag(++tag);
			
		}
		
	};
	
	private void setViewEnable(boolean enabled) {
		ibBtnCamera.setEnabled(enabled);
		ibBtnGridline.setEnabled(enabled);
		ibBtnSwitch.setEnabled(enabled);
		ibBtnFlashing.setEnabled(enabled);
	}
	private void takePicture() {
		/*int width = getWindowManager().getDefaultDisplay().getWidth();
	    Camera.Parameters params = mCamera.mCameraInstance.getParameters();
	    params.setPictureSize(width, width);
	    params.setRotation(90);//TODO
	    mCamera.mCameraInstance.setParameters(params);*/
	    mCamera.mCameraInstance.takePicture(null, null,
	            new Camera.PictureCallback() {
	                @Override
	                public void onPictureTaken(byte[] data, final Camera camera) {
	                	setViewEnable(true);
	
	                    final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
	                    if (pictureFile == null) {
	                        Log.d("ASDF", "Error creating media file, check storage permissions");
	                        return;
	                    }
	
	                    try {
	                        FileOutputStream fos = new FileOutputStream(pictureFile);
	                        fos.write(data);
	                        fos.close();
	                    } catch (FileNotFoundException e) {
	                        Log.d("ASDF", "File not found: " + e.getMessage());
	                    } catch (IOException e) {
	                        Log.d("ASDF", "Error accessing file: " + e.getMessage());
	                    }
	                 // Adding Exif data for the orientation. For some strange reason the
	        			// ExifInterface class takes a string instead of a file.
	        			/*try {
	        				ExifInterface exif = new ExifInterface(pictureFile.getAbsolutePath());
	        				exif.setAttribute(ExifInterface.TAG_ORIENTATION, "" + orientation);
	        				exif.saveAttributes();
	        			} catch (IOException e) {
	        				e.printStackTrace();
	        			}*/
	                    data = null;
	                    Intent intent = new Intent(context, PhotoEditorActivity.class);
	                    intent.putExtra("path", pictureFile.getAbsolutePath());
	                    intent.putExtra("ConfigInfo", getIntent().getSerializableExtra("ConfigInfo"));
        				startActivity(intent);
        				finish();
	                    /*UriUtil.getUrifromFile(context, pictureFile, new ScanFileListener() {
							@Override
							public void onScanCompleted(String path, Uri uri) {
								Intent intent = new Intent(context, PhotoEditorActivity.class);
		        				intent.setData(uri);
			                    //intent.putExtra("path", pictureFile.getAbsolutePath());
		        				startActivity(intent);
		        				finish();
								
							}
						});*/
	                }
	            });
	}
	
	 
	public static final int MEDIA_TYPE_IMAGE = 1;
	public static final int MEDIA_TYPE_VIDEO = 2;
	
	private static File getOutputMediaFile(final int type) {
	    // To be safe, you should check that the SDCard is mounted
	    // using Environment.getExternalStorageState() before doing this.
	
	    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
	            Environment.DIRECTORY_PICTURES), "FamilyCamera");
	    // This location works best if you want the created images to be shared
	    // between applications and persist after your app has been uninstalled.
	
	    // Create the storage directory if it does not exist
	    if (!mediaStorageDir.exists()) {
	        if (!mediaStorageDir.mkdirs()) {
	            Log.d("MyCameraApp", "failed to create directory");
	            return null;
	        }
	    }
	
	    // Create a media file name
	    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
	    File mediaFile;
	    if (type == MEDIA_TYPE_IMAGE) {
	        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
	                "IMG_" + timeStamp + ".jpg");
	    } else if (type == MEDIA_TYPE_VIDEO) {
	        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
	                "VID_" + timeStamp + ".mp4");
	    } else {
	        return null;
	    }
	
	    return mediaFile;
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		mCamera.onPause();
	}

	@Override
	protected void onPause() {
		super.onPause();
		mCamera.onPause();
		sensorManager.unregisterListener(this);
	}

	@Override
	protected void onResume() {
		super.onResume();
		mCamera.onResume();
		sensorManager.registerListener(this, 
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
				SensorManager.SENSOR_DELAY_NORMAL);
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		
		int t = this.getResources().getConfiguration().orientation ;
        if(t == Configuration.ORIENTATION_LANDSCAPE){
        }else if(t ==Configuration.ORIENTATION_PORTRAIT){
        }
	       
		super.onConfigurationChanged(newConfig);
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		
	}

	/**
	 * Putting in place a listener so we can get the sensor data only when
	 * something changes.
	 */
	public void onSensorChanged(SensorEvent event) {
		synchronized (this) {
			if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
				RotateAnimation animation = null;
				if (event.values[0] < 4 && event.values[0] > -4) {
					if (event.values[1] > 0 && orientation != ExifInterface.ORIENTATION_ROTATE_90) {
						// UP
						orientation = ExifInterface.ORIENTATION_NORMAL;//90
						animation = getRotateAnimation(0);//270
						degrees = 0;
					} else if (event.values[1] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_270) {
						// UP SIDE DOWN
						orientation = ExifInterface.ORIENTATION_ROTATE_180;//270
						animation = getRotateAnimation(180);//90
						degrees = 180;
					}
				} else if (event.values[1] < 4 && event.values[1] > -4) {
					if (event.values[0] > 0 && orientation != ExifInterface.ORIENTATION_NORMAL) {
						// LEFT
						orientation = ExifInterface.ORIENTATION_ROTATE_270;//0
						animation = getRotateAnimation(90);//0
						degrees = 90;
					} else if (event.values[0] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_180) {
						// RIGHT
						orientation = ExifInterface.ORIENTATION_ROTATE_90;//180
						animation = getRotateAnimation(270);//180
						degrees = 270;
					}
				}
				if (animation != null) {
					ibBtnClose.startAnimation(animation);
					ibBtnGridline.startAnimation(animation);
					ibBtnSwitch.startAnimation(animation);
					ibBtnFlashing.startAnimation(animation);
				}
			}

		}
	}

	/**
	 * Calculating the degrees needed to rotate the image imposed on the button
	 * so it is always facing the user in the right direction
	 * 
	 * @param toDegrees
	 * @return
	 */
	private RotateAnimation getRotateAnimation(float toDegrees) {
		float compensation = 0;

		if (Math.abs(degrees - toDegrees) > 180) {
			compensation = 360;
		}

		// When the device is being held on the left side (default position for
		// a camera) we need to add, not subtract from the toDegrees.
		if (toDegrees == 0) {
			compensation = -compensation;
		}

		// Creating the animation and the RELATIVE_TO_SELF means that he image
		// will rotate on it center instead of a corner.
		RotateAnimation animation = new RotateAnimation(degrees, toDegrees - compensation, 
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

		// Adding the time needed to rotate the image
		animation.setDuration(250);

		// Set the animation to stop after reaching the desired position. With
		// out this it would return to the original state.
		animation.setFillAfter(true);

		return animation;
	}
	
	
	private class CameraLoader {
		private final int expectWidth = 1024;
		private final int expectHeight = 768;
        private int mCurrentCameraId = 0;
        private Camera mCameraInstance;

        public void onResume() {
            setUpCamera(mCurrentCameraId);
        }

        public void onPause() {
            releaseCamera();
        }

        public void switchCamera() {
            releaseCamera();
            mCurrentCameraId = (mCurrentCameraId + 1) % mCameraHelper.getNumberOfCameras();
            setUpCamera(mCurrentCameraId);
        }
        
        public void setFlashMode(String mode) {
        	Parameters parameters = mCameraInstance.getParameters();
        	parameters.setFlashMode(mode);
            mCameraInstance.setParameters(parameters);
            mCameraInstance.startPreview();
        }

        private void setUpCamera(final int id) {
            mCameraInstance = getCameraInstance(id);
            Parameters parameters = mCameraInstance.getParameters();
            // TODO adjust by getting supportedPreviewSizes and then choosing
            // the best one for screen size (best fill screen)
            List<Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
            List<Size> mSupportedPictureSizes = parameters.getSupportedPictureSizes();
            Size mPreviewSize = null;
            Size mPictureSize = null;
            if (mSupportedPreviewSizes != null) {
   	            mPreviewSize = getOptimalPreviewSize2(mSupportedPreviewSizes);
   	        }
            if (mSupportedPictureSizes != null) {
            	mPictureSize = getOptimalPictureSize(mSupportedPictureSizes, 
            			mPreviewSize);
   	        }
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
            parameters.setPictureFormat(ImageFormat.JPEG);//PixelFormat.JPEG
            /*if (parameters.getSupportedFocusModes().contains(
                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {//PICTURE "continuous-picture"
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }*/
            if (parameters.getSupportedPreviewFormats().contains(ImageFormat.JPEG)) {
            	parameters.setPreviewFormat(ImageFormat.JPEG); 
            }
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
            
            int orientation = mCameraHelper.getCameraDisplayOrientation(
                    CustomCameraNewActivity.this, mCurrentCameraId);
            CameraInfo2 cameraInfo = new CameraInfo2();
            mCameraHelper.getCameraInfo(mCurrentCameraId, cameraInfo);
            boolean flipHorizontal = cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT
                    ? true : false;
            mCameraInstance.setDisplayOrientation(orientation);
            //parameters.setRotation(flipHorizontal?270:90);
            int rotation = mCameraHelper.getCameraRotation(context, mCurrentCameraId);
            parameters.setRotation(rotation);
            
            mCameraInstance.setParameters(parameters);
            ViewGroup.LayoutParams lp = flFlPreview.getLayoutParams();
            //if screenOrientation is portrait 
      		lp.height = screenWidth*mPreviewSize.width/mPreviewSize.height;
      		flFlPreview.setLayoutParams(lp);
            
            mPreview = new CameraPreview(CustomCameraNewActivity.this, mCameraInstance);
    		// Adding the camera preview after the FrameLayout and before the button
    		// as a separated element.
    		flFlPreview.removeAllViews();
    		flFlPreview.addView(mPreview, new LayoutParams(LayoutParams.FILL_PARENT,
    				LayoutParams.FILL_PARENT));
        }

        private Size getOptimalPreviewSize2(List<Size> sizes) {
            Size optimalSize = null;
            if (sizes == null) {
            	return null;
            }
            double scale = (double)screenHeight / (double)screenWidth;
            Size size;
            for (int i = 0; i < sizes.size(); i++) {
				size = sizes.get(i);
				double scale2 = (double)size.width / (double)size.height ;
				if ( scale - scale2 > 0.2 ) {
					if (optimalSize == null) {
						optimalSize = size;
					}else {
						if (optimalSize.height < size.height) {
							optimalSize = size;
						}
					}
				}
			}
            return optimalSize;
        }
        
        private Size getOptimalPictureSize(List<Size> picSizes, Size preSize) {
            
            if (picSizes == null || preSize == null) {
            	return null;
            }
            Size optimalSize = null;
            int w = preSize.width;
            int h = preSize.height;
            //because Size.width > Size.height
            double scale = (double)w / (double)h;
            
            if (optimalSize == null) {
                for (Size size : picSizes) {
					double scale2 = (double)size.width / (double)size.height;
					if (Math.abs(scale - scale2) <= 0.02) {
						if (optimalSize == null) {
							optimalSize = size;
						}else {
							if (Math.abs(optimalSize.height - expectHeight) > Math.abs(size.height - expectHeight)) {
								optimalSize = size;
							}
						}
					}
                }
            }
            return optimalSize;
        }
        
        /** A safe way to get an instance of the Camera object. */
        private Camera getCameraInstance(final int id) {
            Camera c = null;
            try {
                c = mCameraHelper.openCamera(id);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return c;
        }

        private void releaseCamera() {
        	if (mCameraInstance != null) {
        		mCameraInstance.stopPreview();
        		mCameraInstance.setPreviewCallback(null);
                mCameraInstance.release();
                mCameraInstance = null;
			}
        }
    }
}